package com.ruoyi.ade.llm.chunk;

import com.ruoyi.ade.llm.chunk.pattern.PatternCondition;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 正则匹配分块
 */
public class ChunkByPatternService implements IChunkService {

    @Override
    public List<String> chunk(String doc, IAbstractChunkRequest request) {
        doc = doc.replaceAll("\n", "");
        ChunkByPatternRequest req = (ChunkByPatternRequest) request;
        List<PatternCondition> patterns = req.getPatterns();
        List<String> list = new ArrayList<String>();
        for (PatternCondition condition : patterns) {
            list.addAll(condition.match(doc));
        }
        Set<String> result = new HashSet<String>();
        if (list.size() == 0)
            return new ArrayList<String>(result);

        Set<String> removes = new HashSet<String>();
        ;  //需要替换出去的
        boolean exist = false;
        for (String s : list) {
            removes.clear();
            if (s.length() > 120) continue; //超过120个字符的不考虑
            //判断是否存在
            exist = false;
            //分析结果中的字符串： 判断是否需要删掉已有的
            for (String entity : result) {

                if (entity.equals(s)) {   //结果中已经有了   则下一个
                    exist = true;
                    break;
                } else if (entity.contains(s)) {   //如果 结果中包含了当前分析的  取短的  移除结果中的
                    removes.add(entity);
                } else if (s.contains(entity)) {  //如果当前分析的包含了结果中的  取短的 保留结果中的
                    exist = true;
                    break;
                } else if (hasOverlap(s, entity)) {  //如果两个有交叠   判断这两个字符串是否有连续交叠  有连续交叠则计算交叠率
                    //计算两个重叠字符串数
                    double coord = calculateOverlapRate(entity, s);
                    if (coord > 0.3) {
                        if (entity.length() < s.length()) {  //保留短的   如果结果中就是短的 那么当前分析的句子就不要了
                            exist = true;
                            break;
                        } else {                           //如果当前分析的句子是短的   那么原来结果中的就要移除掉
                            removes.add(entity);
                        }
                    }
                }
            }
            if (exist) continue;
            result.add(s);
            result.removeAll(removes);
        }
        return new ArrayList<String>(result);
    }

    /**
     * 计算两个字符串的最长连续公共子串的长度
     *
     * @param str1 第一个字符串
     * @param str2 第二个字符串
     * @return 最长连续公共子串的长度
     */
    private int findLongestCommonSubstringLength(String str1, String str2) {
        int maxLength = 0;
        int[][] dp = new int[str1.length() + 1][str2.length() + 1];

        // 动态规划填充dp数组
        for (int i = 1; i <= str1.length(); i++) {
            for (int j = 1; j <= str2.length(); j++) {
                if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                    maxLength = Math.max(maxLength, dp[i][j]);
                }
            }
        }

        return maxLength;
    }

    /**
     * 计算两个字符串的重叠率（基于最长连续公共子串）
     *
     * @param str1 第一个字符串
     * @param str2 第二个字符串
     * @return 重叠率（0到1之间的小数）
     */
    private double calculateOverlapRate(String str1, String str2) {
        int maxLength = findLongestCommonSubstringLength(str1, str2);
        int minLength = Math.min(str1.length(), str2.length());
        return (double) maxLength / minLength;
    }

    /**
     * 判断两个字符串 头尾是否有交叠
     *
     * @param str1
     * @param str2
     * @return
     */
    private boolean hasOverlap(String str1, String str2) {
        int lenA = str1.length();
        int lenB = str2.length();

        // 检查a的所有可能末尾子串是否与b的开头匹配
        for (int i = 1; i <= Math.min(lenA, lenB); i++) {
            String suffixA = str1.substring(lenA - i);
            if (str2.startsWith(suffixA)) {
                return true;
            }
        }

        // 检查b的所有可能末尾子串是否与a的开头匹配
        for (int i = 1; i <= Math.min(lenA, lenB); i++) {
            String suffixB = str2.substring(lenB - i);
            if (str1.startsWith(suffixB)) {
                return true;
            }
        }

        return false;
    }


}
